﻿package render3d.adapters 
{
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Scene3D;
	import alternativa.engine3d.core.Sprite3D;
	import alternativa.engine3d.display.View;
	import alternativa.engine3d.materials.Material;
	import alternativa.engine3d.materials.SpriteMaterial;
	import alternativa.engine3d.materials.SpriteTextureMaterial;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.primitives.Box;
	import alternativa.engine3d.primitives.Plane;
	import alternativa.types.Point3D;
	import alternativa.types.Texture;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import render3d.adapters.abstract.Render3DAdapterAbstract;
	import render3d.CrossEngineObject3D;
	import render3d.interfaces.IRender3DAdapter;
	import render3d.interfaces.IRender3DForObject3D;
	
	/**
	 * Alternativa3D 5.6 Adapter
	 * @author Exey Panteleev
	 */
	public class Alternativa3DAdapter extends Render3DAdapterAbstract implements IRender3DAdapter, IRender3DForObject3D
	{
		override public function get GRID_Y_FIX():int { return 0 };
		
		private var scene:Scene3D;
		private var camera:Camera3D;
		private var view:View;

		public function Alternativa3DAdapter() 
		{
			initScene();
		}
		
		public function initScene():void 
		{
			scene = new Scene3D();
			scene.root = new Object3D();
			camera = new Camera3D();
			scene.root.addChild(camera);
			view = new View(camera);
			viewContainer.addChild(view);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Camera 
		//
		//--------------------------------------------------------------------------
		
		public function setCameraPosition(x:Number = NaN, y:Number = NaN, z:Number = NaN):void 
		{
			if (!isNaN(x)) camera.x = x;
			if (!isNaN(y)) camera.y = y;
			if (!isNaN(z)) camera.z = z;
		}
		
		public function moveCamera(forwardSpeed:Number, rightSpeed:Number, jumpSpeed:Number):void 
		{
			//trace(forwardSpeed, rightSpeed, jumpSpeed)
			camera.x += rightSpeed;
			camera.y += forwardSpeed;
			camera.z += jumpSpeed;
		}
		
		public function rotateCamera(x:Number = NaN, y:Number = NaN, z:Number = NaN):void 
		{
			if (!isNaN(x)) camera.rotationX = x*toRADIANS;
			if (!isNaN(y)) camera.rotationY = y*toRADIANS;
			if (!isNaN(z)) camera.rotationZ = z*toRADIANS;
		}
		
		public function lookCamera(mouseX:Number, mouseY:Number):void 
		{
			camera.rotationX -= mouseY * toRADIANS;
			camera.rotationZ -= mouseX * toRADIANS;
		}
		
		public function getCameraTransformation():Matrix3D 
		{
			var matrix:Matrix3D = new Matrix3D();
			var components:Vector.<Vector3D> = new Vector.<Vector3D>();
			components[0] = new Vector3D(camera.x, camera.y, camera.z);
			components[1] = new Vector3D(camera.rotationX, camera.rotationY, camera.rotationZ);
			components[2] = new Vector3D(1, 1, 1);
			matrix.recompose(components);
			return matrix;
		}
		
		public function getCameraHeight():Number 
		{
			return camera.z;
		}

		public function getCameraPanAngle():Number 
		{
			return camera.rotationZ;
		}
		
		//--------------------------------------------------------------------------
		//
		//  3D Objects 
		//
		//--------------------------------------------------------------------------
		
		public function createPlane(bitmapData:BitmapData, width:int, height:int, type:String = ""):CrossEngineObject3D 
		{
			var plane:Plane = new Plane(width, height, 1, 1, false);
			plane.setMaterialToSurface(new TextureMaterial(new Texture(bitmapData), 1, false, true, BlendMode.NORMAL), "front")
			var crossEngineObject3D:CrossEngineObject3D
			//var object3dConatiner:Object3D
			//if (type == "wall") 
			//{
				// fix plane for right sorting
				//object3dConatiner = new Object3D();
				//plane.y = -bitmapData.height*0.5;
				//object3dConatiner.addChild(plane);
				//crossEngineObject3D = new CrossEngineObject3D(this, object3dConatiner);
			//}
			//else 
			//{
				crossEngineObject3D = new CrossEngineObject3D(this, plane);
			//}			
			 
			return crossEngineObject3D;
		}
		
		public function createSkybox(back:BitmapData, left:BitmapData, front:BitmapData, right:BitmapData, top:BitmapData, bottom:BitmapData):CrossEngineObject3D
		{
			var backMaterial:TextureMaterial = new TextureMaterial(new Texture(back), 1, false, true, BlendMode.NORMAL);
			var leftMaterial:TextureMaterial = new TextureMaterial(new Texture(left), 1, false, true, BlendMode.NORMAL);
			var frontMaterial:TextureMaterial = new TextureMaterial(new Texture(front), 1, false, true, BlendMode.NORMAL);
			var rightMaterial:TextureMaterial = new TextureMaterial(new Texture(right), 1, false, true, BlendMode.NORMAL);
			var topMaterial:TextureMaterial = new TextureMaterial(new Texture(top), 1, false, true, BlendMode.NORMAL);
			var bottomMaterial:TextureMaterial = new TextureMaterial(new Texture(bottom), 1, false, true, BlendMode.NORMAL);
			var skybox:Box = new Box(20000, 20000, 20000, 1, 1, 1, true)
			skybox.setMaterialToSurface(backMaterial, "back");
            skybox.setMaterialToSurface(rightMaterial, "left"); // swapped
            skybox.setMaterialToSurface(frontMaterial, "front");
            skybox.setMaterialToSurface(leftMaterial, "right"); // swapped
            skybox.setMaterialToSurface(topMaterial, "top");			
			skybox.setMaterialToSurface(bottomMaterial, "bottom");
			var crossEngineObject3D:CrossEngineObject3D = new CrossEngineObject3D(this, skybox);
			return crossEngineObject3D;			
		}
		
		public function createSprite3D(bitmapData:BitmapData, type:String = ""):CrossEngineObject3D
		{
			var sprite3D:Sprite3D = new Sprite3D();
						
			var crossEngineObject3D:CrossEngineObject3D;			
			if (type == "monster") 
			{
				// fix sprite for right rendreing
				sprite3D.material = new SpriteTextureMaterial(new Texture(bitmapData), 1, false, BlendMode.NORMAL, 0.5, 1)
				var object3dConatiner:Object3D = new Object3D();
				sprite3D.y = -bitmapData.height * 0.5;
				object3dConatiner.addChild(sprite3D);
				crossEngineObject3D = new CrossEngineObject3D(this, object3dConatiner);
			}
			else
			{
				sprite3D.material = new SpriteTextureMaterial(new Texture(bitmapData), 1, false, BlendMode.NORMAL, 0.5, 0.5)
				crossEngineObject3D = new CrossEngineObject3D(this, sprite3D);
			}
			return crossEngineObject3D;	
		}
		
		//--------------------------------------------------------------------------
		//
		//  Common
		//
		//--------------------------------------------------------------------------
		
		public function update():void 
		{
			this.scene.calculate();
		}
		
		public function resize(stageWidth:int, stageHeight:int):void 
		{
			view.width = stageWidth;
			view.height = stageHeight;
			scene.calculate();
		}
		
		//--------------------------------------------------------------------------
		//
		//  INTERFACE render3d.interfaces.IRender3DForObject3D
		//
		//--------------------------------------------------------------------------
		
		public function copyTransformation(sourceMatrix3D:Matrix3D, targetObject3D:*):void 
		{
			var matrix:Matrix3D = Matrix3D(sourceMatrix3D)
			var components:Vector.<Vector3D> = matrix.decompose();
			Object3D(targetObject3D).x = components[0].x;
			Object3D(targetObject3D).y = components[0].y;
			Object3D(targetObject3D).z = components[0].z;
			
			Object3D(targetObject3D).rotationX = components[1].x+Math.PI*0.5;
			Object3D(targetObject3D).rotationY = components[1].y;
			Object3D(targetObject3D).rotationZ = components[1].z;
			
			Object3D(targetObject3D).scaleX = components[2].x;
			Object3D(targetObject3D).scaleY = components[2].y;
			Object3D(targetObject3D).scaleZ = components[2].z;
		}
		
		public function copyPosition(sourceMatrix3D:Matrix3D, targetObject3D:*):void 
		{
			var components:Vector.<Vector3D> = sourceMatrix3D.decompose();
			Object3D(targetObject3D).x = components[0].x;
			Object3D(targetObject3D).y = components[0].y;
			Object3D(targetObject3D).z = components[0].z;
		}

		public function changeTexture( bitmapData:BitmapData, targetObject3D:* ):void 
		{
			var material:*;
			if (targetObject3D is Object3D)
				targetObject3D = Object3D(targetObject3D).children.toArray()[0]
			if(targetObject3D is Sprite3D)
				material = Sprite3D(targetObject3D).material;
			if (!material)
				return;
			material.texture = new Texture(bitmapData);
		}
		
		//--------------------------------------------------------------------------
		//
		//  INTERFACE render3d.interfaces.abstract.IRender3DAbstract
		//
		//--------------------------------------------------------------------------
		
		public function addChild(child:CrossEngineObject3D):void 
		{
			scene.root.addChild(Object3D(child.object3D));
		}
		
		public function removeChild(child:CrossEngineObject3D):void 
		{
			scene.root.removeChild(Object3D(child.object3D));
		}

	}
}